<template>
    <div>
        跳转页面
    </div>
</template>

<script setup lang="jsx">
import {getCurrentInstance, onErrorCaptured} from "vue";
const { proxy } = getCurrentInstance();
console.log(proxy.Test,'代理费用')
//1:原型模式构造函数用用来穿件重复的实例，用来保证性能
function Person(){
    Person.prototype.name="marry";
    Person.prototype.sayName=function (){
        console.log(this.name)
    }
}
const person1=new Person();
const person2=new Person();
console.log(person1.sayName===person2.sayName,'原型模式');
//2:单例模式也就是单例模式只能创建一个实例，如果其中有一个修改那么之前的也会受到影响。
let box;
const createBox=(_a,_b)=>{
    if(!box){
        box={}
    }
    box.a=_a;
    box.b=_b;
    return box;
}
const obj1=createBox(3,6);
console.log(obj1,'打印');
const obj2=createBox(10,20);
console.log(obj1,obj2,'打印树脂·')
//工厂模式也就是相当于我们用同一种方法，但是提供的数值是不一样的.
function restaurant(menu){
    switch (menu){
        case '鱼香肉丝':
            return new YuxiangRouSi();
        case '宫保鸡丁':
            return new GongBaoJiDin();
        default:
            throw new Error('这个菜本店没有');
    }
}
function YuxiangRouSi(){
    this.type="鱼香肉丝"
}
YuxiangRouSi.prototype.eat=function (){
    console.log(this.type+'真想s')
}
function GongBaoJiDin(){
    this.type="宫保鸡丁"
}
GongBaoJiDin.prototype.eat=function (){
    console.log(this.type + ' 让我想起了外婆做的菜~');
}
const dish1 = restaurant('鱼香肉丝');
dish1.eat();
// 鱼香肉丝 真香
class Restauranted{
    static getMenu(menu){
        switch (menu){
            case '鱼香肉丝':
                return new YuXiangRouSied();
            case '宫保鸡丁':
                return new GongBaoJiDined();
            default:
                throw new Error('这个菜本店没有')
        }
    }
}
class YuXiangRouSied{
    constructor() {
        this.type='鱼香肉丝'
    }
    eat(){
        console.log(this.type+'真想这个是累')
    }
}
class  GongBaoJiDined{
    constructor() {
        this.type="宫保鸡丁"
    }
    eat(){
        console.log(this.type + ' 让我想起了外婆做的菜');
    }
}
const dish1s = Restauranted.getMenu('鱼香肉丝');
dish1s.eat();
//上面的有缺陷，因为如果有很多类的话就需要一直创建很雍正;
//下面是讲创建的方法给抽出来了，这样就不用每次都添加方法了
class Restaurantsed{
    constructor() {
        this.menuData={}
    }
    getMenu(menu){
        if(!this.menuData[menu]){
            throw new Error('这个菜本店没有')
        }
        const {type,message}=this.menuData[menu];
        return new Menu(type,message);
    }
    addMenu(menu,type,message){
        if(this.menuData[menu]){
            console.log('已经有这个菜了!');
            return
        }
        this.menuData[menu]={type,message}
    }
    removeMenu(menu){
        if(!this.menuData[menu]) return
        delete this.menuData[menu]
    }
}
class Menu{
    constructor(type,message) {
        this.type=type;
        this.message=message;
    }
    eat(){
        console.log(this.type+this.message,'这个是精简模式')
    }
}
const restaurantsed = new Restaurantsed();
restaurantsed.addMenu('YuXiangRouSi', '鱼香肉丝', ' 真香');
restaurantsed.addMenu('GongBaoJiDin', '宫保鸡丁', ' 让我想起了外婆做的菜');
const dish3=restaurantsed.getMenu('YuXiangRouSi')
dish3.eat();
//下面将菜品抽给抽象出来来当成其父类进行继承
function RestaurantedNode(){}
RestaurantedNode.orderDish=function (type){
    switch (type){
        case '鱼香肉丝':
            return new YuXiangRouSis()
        case '宫保鸡丁':
            return new GongBaoJiDings()
        case '紫菜蛋汤':
            return new ZiCaiDanTangs()
        default:
            throw new Error('本店没有这个')

    }
}
function Dish(){this.kind="菜"}
Dish.prototype.eat = function() { throw new Error('抽象方法不能调用!') };
function YuXiangRouSis(){
    this.type="鱼香肉丝似"
}
YuXiangRouSis.prototype=new Dish();
YuXiangRouSis.prototype.eat=function (){
    console.log(this.type+'类型'+this.kind)
}
function GongBaoJiDings(){
    this.type="宫保鸡丁"
}
GongBaoJiDings.prototype=new Dish();
GongBaoJiDings.prototype.eat=function (){
     console.log(this.type+'类型'+this.kind)
}
const dish5=RestaurantedNode.orderDish('鱼香肉丝');
dish5.eat();
const dish4=RestaurantedNode.orderDish('宫保鸡丁');
dish4.eat();
//类的改造
class RestaurantList{
    static orderDish(type){
        switch (type){
            case '鱼香肉丝':
                return new YuXiangRouSised()
            case '宫保鸡丁':
                return new GongBaoJiDingsed()
            case '紫菜蛋汤':
                return new ZiCaiDanTangsed()
            default:
                throw new Error('本店没有这个')

        }
    }
}
//抽象共产函数将其菜品的公共方法和属性抽象出来了，定义了一个模板
class Dished{  constructor() {

      if (new.target === Dish) {
          throw new Error('抽象类不能直接实例化!')
      }
      this.kind="菜品"
  }
  eat(){
    throw Error('报错')
  }
}
class YuXiangRouSised extends Dished{
    constructor() {
        super();
         this.type="鱼香肉丝"
    }
     eat(){
    console.log(this.type+this.kind,'菜品')
    }
}
class GongBaoJiDingsed extends Dished{
    constructor() {
        super();
        this.type="宫保鸡丁"
    }
    eat(){
        console.log(this.type+this.kind,'菜品')
    }
}
const dish8=RestaurantList.orderDish('鱼香肉丝');
dish8.eat();
const dish9=RestaurantList.orderDish('宫保鸡丁');
dish9.eat();
//抽象模式也就是需要将一个复杂的工厂工程进行拆解
//将构建者的一些零件进行处理
function CarBuilder({color="white",weight=0}){
    this.color=color;
    this.weight=weight
}
CarBuilder.prototype.buildType=function (type){
    switch (type){
        case 'small':
            this.tyreType="小号轮胎"
            this.tyreIntro="正在使用小号轮胎";
            break
        case 'normal':
            this.tyreType="中号轮胎"
            this.tyreIntro="正在使用中号轮胎";
            break
        case 'big':
            this.tyreType="大号轮胎"
            this.tyreIntro="正在使用大号轮胎";
            break

    }
}
CarBuilder.prototype.buildEngine=function (type){
    switch (type){
        case 'small':
            this.engineType = '小马力发动机'
            this.engineIntro = '正在使用小马力发动机'
            break
        case 'normal':
            this.engineType = '中马力发动机'
            this.engineIntro = '正在使用中马力发动机'
            break
        case 'big':
            this.engineType = '大马力发动机'
            this.engineIntro = '正在使用大马力发动机'
            break

    }
}
//相当于进行一个组装，实例化了当前功能把要放入的参数进行放入
function benChiDirector(tyre,engine, param){
    var car=new CarBuilder(param);
    car.buildType(tyre);
    car.buildEngine(engine);
    return car
}
var bechi=benChiDirector('small','big',{color:'red',weight:'1600kg'})
console.log(bechi,'表达式')
//结论
//1:建造者模式是讲建造和组装进行分离，故而分成两个模块其一为建造者，其二为组装者，
class CarBuildered{
    constructor(param) {
        this.param=param
    }
    buildPart1(){
        this.part1="part1";
        return this
    }
    buildPart2(){
        this.part2="part2";
        return this
    }
}
const bechi2=new CarBuildered('param').buildPart1().buildPart2();
console.log(bechi2,'结合链')
//这个是结合链模式也就是用链式调用的方法进行使用每一次都返回自己的实例
//以上设计模式进行总结：
//1:首先是原型模式.原型模式是创建重复对象的，如果有需要重复创建某一个一样的东西的时候就用原型模式。
//2:单例模式也就是只能创建一个实例，如果有一个实例有所改变的话，那么其他的所有实例都会进行改变
//3:工厂模式就是将方法的实现与创建进行分离，将创建封装成一个类，将实现有封装成几个类
//过程步骤：1：创建一个实现类，这个类包括了创建，增加和移除，增加的话放入数组当中里面，然后判断数组有没有,实现的首先接收这个值然后将这个值实例化。
//2:创建菜品类用于放入菜品里面的属性和方法。
//3:实现的话首先新增菜品，然后进行获取菜品的实例就是一套可随时添加的工厂函数了.
//抽象工厂函数。所谓的抽象方法也就是需要定义一个模板用于描述抽象类,也就是下面的方法都需要按照这个抽象类的模板来进行定义实现方法需要进行继承。
//把每个类都需要抽离出其模板
//1：比如上面例子抽象工厂函数首先把饭店的公共方法和属性，还有菜品，汤的公共属性都给抽离了出来
//建造者模式其实跟工厂函数很像.如果有相同的方法不同的执行结果时候就可使用建造者模式

//桥连模式
function Boy(instrument){
    this.sayHi=function (){
        console.log('hi, 我是男生')
    }
    this.playInstrument=function (){
        instrument.play()
    }
}
function Girl(instrument) {
    this.sayHi = function() {
        console.log('hi, 我是女生')
    }

    // 有一个功能叫playInstrument， 没有具体乐器
    this.playInstrument = function() {
        instrument.play()
    }
}
function Piano(){
    this.play=function (){
        console.log('钢琴开始演奏')
    }
}
function Guitar() {
    this.play = function() {
        console.log('吉他开始演奏')
    }
}
let piano = new Piano()
let guitar = new Guitar()
let pianoBoy = new Boy(piano)
pianoBoy.playInstrument()
let guitarGirl = new Girl(guitar)
guitarGirl.playInstrument()
//这种设计模式是将方法与实现进行分离从而让两者有更强的独立性

//外观模式也就是将一些复杂的逻辑封装成一个接口用以外部进行调用
//享元模式也就是运用共享技术来支持大量对象的复用，用以减少对象得数量
// 书的属性
// id
// title
// author
// genre
// page count
// publisher id
// isbn

// 管理所需的额外属性
// checkout date
// checkout member
// due return date
// availability

// 享元（存储内部状态）
function Book(title, author, genre, pageCount, publisherId, isbn) {
    this.title = title;
    this.author = author;
    this.genre = genre;
    this.pageCount = pageCount;
    this.publisherId = publisherId;
    this.isbn = isbn;
}

// 享元工厂（创建/管理享元）
var BookFactory = (function() {
    var existingBooks = {};
    var existingBook = null;

    return {
        createBook: function(title, author, genre, pageCount, publisherId, isbn) {
            // 如果书籍已经创建，，则找到并返回
            // !!强制返回bool类型
            existingBook = existingBooks[isbn];
            if (!!existingBook) {
                return existingBook;
            }
            else {
                // 如果不存在选择创建该书的新实例并保存
                var book = new Book(title, author, genre, pageCount, publisherId, isbn);
                existingBooks[isbn] = book;

                return book;
            }
        }
    }
})();

// 客户端（存储外部状态）
var BookRecordManager = (function() {
    var bookRecordDatabase = {};

    return {
        // 添加新书到数据库
        addBookRecord: function(id, title, author, genre, pageCount, publisherId, isbn,
                                checkoutDate, checkoutMember, dueReturnDate, availability) {
            var book = BookFactory.createBook(title, author, genre, pageCount, publisherId, isbn);

            bookRecordDatabase[id] = {
                checkoutMember: checkoutMember,
                checkoutDate: checkoutDate,
                dueReturnDate: dueReturnDate,
                availability: availability,
                book: book
            }
            console.log(bookRecordDatabase,'李彪')
        },
        updateCheckStatus: function(bookId, newStatus, checkoutDate, checkoutMember, newReturnDate) {
            var record = bookRecordDatabase[bookId];

            record.availability = newStatus;
            record.checkoutDate = checkoutDate;
            record.checkoutMember = checkoutMember;
            record.dueReturnDate = newReturnDate;
        },
        extendCheckoutPeriod: function(bookId, newReturnDate) {
            bookRecordDatabase[bookId].dueReturnDate = newReturnDate;
        },
        isPastDue: function(bookId) {
            var currDate = new Date();

            return currDate.getTime() > Date.parse(bookRecordDatabase[bookId].dueReturnDate);
        }
    };
})();


// isbn号是书籍的唯一标识，以下三条只会创建一个book对象
BookRecordManager.addBookRecord(1, 'x', 'x', 'xx', 300, 10001, '100-232-32');   // new book
BookRecordManager.addBookRecord(2, 'xx', 'xx', 'xx', 300, 10001, '100-232-321');
BookRecordManager.addBookRecord(3, 'xxx', 'xxx', 'xxx', 300, 10001, '100-232-322');
//下面的即使传递的参数一样返回的还是第一个的实例
//适配器模式
var chinaPlug={
    type:'中国插头',
    chinaInPlug(){
        console.log('开始供电')
    }
}
var japanPlug = {
    type: '日本插头',
    japanInPlug() {
        console.log('开始供电');
    }
};
function japanPlugAdapter(plug){
    return {
        chinaInPlug(){
            return plug.japanInPlug()
        }
    }
}
japanPlugAdapter(japanPlug).chinaInPlug();
// 原来的树形结构
const oldTreeData = [
    {
        name: '总部',
        place: '一楼',
        children: [
            {
                name: '财务部',
                place: '二楼'
            },
            {
                name: '生产部',
                place: '三楼'
            },
            {
                name: '开发部',
                place: '三楼',
                children: [
                    {
                        name: '软件部',
                        place: '四楼',
                        children: [
                            { name: '后端部', place: '五楼' },
                            { name: '前端部', place: '七楼' },
                            { name: '技术部', place: '六楼' }
                        ]
                    },
                    {
                        name: '硬件部',
                        place: '四楼',
                        children: [
                            { name: 'DSP部', place: '八楼' },
                            { name: 'ARM部', place: '二楼' },
                            { name: '调试部', place: '三楼' }
                        ]
                    }
                ]
            }
        ]
    }
];
function treeDataAdapter(treeData,lastArrayData=[]){
    treeData.forEach(item=>{
        if(item.children){
            treeDataAdapter(item.children,lastArrayData)
        }
        const {name,place}=item;
        lastArrayData.push({name,place})
    })
    return lastArrayData
}
var data=treeDataAdapter(oldTreeData);
console.log(data)
//所谓的适配器模式就是需要把数据在不动原本的情况吧数据改写成想要的样子
//代理模式：虚拟代理需要将一些开销比较大的对象延迟执行;
const myImage = (function () {
    const imgNode = document.createElement('img');
    document.body.appendChild( imgNode );
    return {
        setSrc: function(src) {
            imgNode.src = src;
        }
    }
})();
const proxyImage=(function (){
    const img=new Image();
    img.onload=()=>{
        setTimeout(()=>{
            myImage.setSrc(img.src)
        },2000)
    }
    return {
        setSrc:src=>{
            myImage.setSrc('http://seopic.699pic.com/photo/40167/3716.jpg_wh1200.jpg');
            img.src = src;
        }
    }
})()
proxyImage.setSrc('http://seopic.699pic.com/photo/40167/7823.jpg_wh1200.jpg');
//缓存代理也就是如果会断接口请求同一个页面，如果在同一个页面的话，那么就行缓存;
const getFib=(number)=>{
      if(number<=2){
          return 1
}else{
    return getFib(number-1)+getFib(number-2)
}
}

const getCacheProxy=(fn,cache=new Map())=>{
    return new Proxy(fn,{
        apply(target,context,args){
            const argsString=args.join('');
            if(cache.has(argsString)){
                console.log(`输出${args}的缓存结果: ${cache.get(argsString)}`);
                return cache.get(argsString)
            }
            const result=fn(...args);
            cache.set(argsString,result);
            return result
        }
    })
}
const Del=getCacheProxy(getFib);
const del1=Del(40);
console.log(del1,'表达')
//上面的缓存代理也就是如果调用的是同一个页面那么就不会从新执行而是直接走缓存
//apply方法拦截函数的掉哦用也就是在调用proxy的方法的时候回进入apply里面去，这个时候放入原本的代理对象用来计算
//所谓的组合模式其实是将树状结构的数组进行整理归纳,进行的对象组合
//用来创造对象里面放着子对象的集合并且只有增加和扫描两个方法
var createFolder=function (name){
    return {
        name: name,
        _children: [],
        add(fileOrFolder) {
            this._children.push(fileOrFolder)
        },
        scan(cb) {
            this._children.forEach(function (child) {
                child.scan(cb)
            })
        }
    }
}
//用来创造当前文件
var createFile=function (name,size){
     return {
         name:name,
         size:size,
         add(){
             throw new Error('文件下面不能再添加文件')
         },
        scan(cb){
             console.log('执行')
             cb(this)
        }
     }
}
var foldMovies = createFolder('电影')

// 创建子文件夹，并放入根文件夹
var foldMarvelMovies = createFolder('漫威英雄电影')
foldMovies.add(foldMarvelMovies)

var foldDCMovies = createFolder('DC英雄电影')
foldMovies.add(foldDCMovies)
//上面的就是一个大文件里面放入了两个小文件并且格式数据都相同只不过放到了children里面了
// 为两个子文件夹分别添加电影
foldMarvelMovies.add(createFile('钢铁侠.mp4', 1.9))
foldMarvelMovies.add(createFile('蜘蛛侠.mp4', 2.1))
foldMarvelMovies.add(createFile('金刚狼.mp4', 2.3))
foldMarvelMovies.add(createFile('黑寡妇.mp4', 1.9))
foldMarvelMovies.add(createFile('美国队长.mp4', 1.4))

foldDCMovies.add(createFile('蝙蝠侠.mp4', 2.4))
foldDCMovies.add(createFile('超人.mp4', 1.6))
//在两个小文件下面放入数据其返回为对象格式
console.log('size 大于2G的文件有：')
foldMovies.scan(function (item) {
    if (item.size > 2) {
        console.log('name:' + item.name + ' size:' + item.size + 'GB')
    }
})
//这个时候就需要进行从对象当中来取这些数据了，第一层就便利下面的刘昂个文件夹，然后将这两个扫描又调用了里面文件的方法就进入到了里面这个时候
//首先创建一个跟对象然后创建两个一模一样的对象放到了这个数组当中，然后再讲这两个对象里面再添加问你件，然后通过访问跟文件一层层讲数据传递下去然后过滤打印
//装饰器模式也就是将原有的代码不想修改，从而在增加新的方法；
// 装饰器函数，它的第一个参数是目标类
function Decorator(target, name, descriptor) {
    let originalMethod = descriptor.value
    descriptor.value = function() {
        console.log('我是Func的装饰器逻辑')
        console.log('我是新的逻辑')
        return originalMethod.apply(this, arguments)
    }
    return descriptor
}

class HorribleCode {
    @Decorator // 将装饰器“安装” 到HorribleCode上
    control() {
        console.log('我是一堆老逻辑')
    }
}

// 验证装饰器是否生效
const horribleCode = new HorribleCode()
horribleCode.control()
</script>

<style scoped>

</style>
